import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { UserDto } from 'src/app/models/sys/user.dto';
import { FormBuilder } from '@angular/forms';
import { NzMessageService } from 'ng-zorro-antd/message';
import { ApiService } from 'src/app/services/api.service';
import { RoleDto } from 'src/app/models/sys/role.dto';
import { NzFormatEmitEvent, NzTreeComponent, NzTreeNode, NzTreeNodeOptions } from 'ng-zorro-antd/tree';
import { RoleQueryParam } from 'src/app/models/param/role-query.param';
import { Consts } from 'src/app/consts/consts';
import { NzButtonSize } from 'ng-zorro-antd/button';
import { UserPermParam } from 'src/app/models/param/user-perm.param';
import { NzTreeNodeKey } from 'ng-zorro-antd/core/tree';

const KEY_PREFIX = "app_";

@Component({
  selector: 'app-assign-perms',
  templateUrl: './assign-perms.component.html',
  styleUrl: './assign-perms.component.less'
})
export class AssignPermsComponent implements OnInit {
  @Input() userSubject!: BehaviorSubject<UserDto>;
  @Output() assignEvent = new EventEmitter<boolean>();

  @ViewChild('nzTreeComponent') tree!: NzTreeComponent;

  user: UserDto = { userId: 0, username: '', enabled: false, roles: []};
  roleNodes: NzTreeNodeOptions[] = [];

  defaultCheckedKeys: NzTreeNodeKey[] = [];
  defaultSelectedKeys: NzTreeNodeKey[] = [];
  defaultExpandedKeys = [];

  selectedNodes: NzTreeNode[] = [];
  preCheckedKeys = new Set<string>();

  // Key是clientId，以clientId作为虚拟父节点。当clientId被选中时，应替换为其下的所有子节点。
  map: Map<string, RoleDto[]> = new Map();
  // 虚构的权限父节点，分配节点时要去点这些keys
  ignoreKeys = new Array<string>();

  constructor(private _api: ApiService,
    private _fb: FormBuilder,
    private _message: NzMessageService) { }

  ngOnInit(): void {
    
    this.getRoles();
  }

  reset() {
    this.roleNodes = [];
    this.defaultCheckedKeys = [];
    this.defaultSelectedKeys = [];
    this.defaultExpandedKeys = [];
    this.selectedNodes = [];
    this.ignoreKeys = [];
    this.map = new Map();
  }

  nzClick(event: NzFormatEmitEvent): void {
    console.log(event);
  }

  nzCheck(event: NzFormatEmitEvent): void {
    console.log(`nzCheck ${event.keys}`);
  //  this.selectedNodes = event.checkedKeys?? [];
  }

  getRoles() {
    const param = new RoleQueryParam();

    this._api.getRoleList(param).subscribe((resp) => {
      if (resp.code == Consts.RESP_OK && resp.data) {
        this.buildRoleTree(resp.data);

        // nz-tree准备好之后再设置默认值
        this.userSubject.subscribe((value) => {
          this._api.getUserDetail(value.userId).subscribe((resp) => {
            if (resp.code == Consts.RESP_OK && resp.data) {
              this.user = resp.data;
              const checkedKeys = this.user.roles.map(x => x.roleId.toString());
              this.preCheckedKeys = new Set<string>();
              for (const selectedKey of checkedKeys) {
                this.preCheckedKeys.add(selectedKey);
              }
              console.log(`set default keys to ${checkedKeys.join(',')}`);
        
              this.defaultCheckedKeys = Array.from(this.preCheckedKeys);
            }
          })
        });
      }
    });
  }

  onAssign(e?: MouseEvent) {
    e?.preventDefault();

    if (this.user == null) {
      this._message.warning("No user parameter");
      return;
    }

    const nodes = this.tree.getCheckedNodeList();
    console.log(`nodes contains ${nodes.map(x => x.key).join(',')}`);
    const param = new UserPermParam();
    param.userId = this.user.userId;

    // 选中的虚拟节点
    const clientIds = nodes.filter(x => this.ignoreKeys.includes(x.key)).map(x => x.key);
    console.log(`checked virtual id ${clientIds.join(',')}`);

    // 选中的非虚拟节点
    const roleIds = nodes.filter(x => !this.ignoreKeys.includes(x.key)).map(x => Number(x.key));
    const childrenRoleIds = this.getChildrenKeys(clientIds);
    console.log(`virtual to childrenIds ${childrenRoleIds.join(',')}`);
    const allRoleIds = new Set<number>();
    for (const roleId of roleIds) {
      allRoleIds.add(roleId);
    }
    for (const childRoleId of childrenRoleIds) {
      allRoleIds.add(childRoleId);
    }

    param.roleIds = Array.from(allRoleIds);
    console.log(`onAssign checked id: ${param.roleIds.join(',')}`);
    console.log(`onAssign default checked: ${this.defaultCheckedKeys.join(',')}`);

    this._api.assignRoles(param).subscribe((resp) => {
      if (resp.code == Consts.RESP_OK) {
        this._message.info("Assign user role OK");
        this.assignEvent.emit(true);
        this.reset();
      } else {
        this._message.info("Assign user roles error: " + resp.message);
      }
    });
  }

  getChildrenKeys(clientIds: string[]): number[] {
    const result: number[] = [];
    for (const clientId of clientIds) {
      const existRoles = this.map.get(clientId);
      if (existRoles != null) {
        for (const existRole of existRoles) {
          result.push(existRole.roleId);
        }
      }
    }

    return result;
  }

  onCancel() {
    this.reset();
    this.assignEvent.emit(false);
  }

  buildRoleTree(roles: RoleDto[]) {
    this.map = this.rolesToMap(roles);

    for (const key of this.map) {
      console.log(`map has key ${key[0]}`)
    }
    this.mapToTreeNodes(this.map);
  }

  // 以KEY_PREFIX+clientId作为键.此键也作为虚拟节点的key
  rolesToMap(roles: RoleDto[]): Map<string, RoleDto[]> {
    const map: Map<string, RoleDto[]> = new Map();
    console.log(`rolesToMap with ${roles.length}`);
    for (const role of roles) {
      const clientId = KEY_PREFIX + role.clientId;
      if (clientId == null || clientId.length === 0) {
        continue;
      }

      let existRoles = map.get(clientId);
      if (existRoles == null) {
        existRoles = [role];
//        console.log(`add new map key ${clientId}`);
        map.set(clientId, existRoles);
      } else {
//        console.log(`add role ${role.roleKey} to exist ${clientId}`);
        existRoles.push(role);
      }
    }

    return map;
  }

  mapToTreeNodes(map: Map<string, RoleDto[]>) {
    this.roleNodes = [];
    this.ignoreKeys = [];

    for (const [key, roles] of map) {
      const children: NzTreeNodeOptions[] = [];
      for (const role of roles) {
        const node = {
          title: role.roleName,
          key: role.roleId!.toString(),
          disabled: false,
          isLeaf: true,
          checked: false
        };
        if (this.preCheckedKeys.has(role.roleId.toString())) {
          console.log(`found pre selected key ${role.roleId}`);
          node.checked = true;
        }

        children.push(node);
      }

      const parent = {
        title: key,
        key: key,
        children: children,
        isLeaf: false,
        selectable: false,
        disabled: false
      };


      this.roleNodes.push(parent);
      console.log(`push ignore keys ${parent.key}`);
      this.ignoreKeys.push(parent.key);
    }
  }
}
